﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Security.Principal;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
using System.Web.UI;
using App.Account.Services;
using StructureMap;
using App.Account.Models;
using App.Utility.Services;
using App.Utility.Controllers;
using App.Account.Properties;
using App.Utility.Paging;
using App.Utility.Pathing;

namespace App.Account.Controllers
{

    [HandleError]
    [OutputCache(Location = OutputCacheLocation.None)]
    public class AccountController : Controller
    {

        // This constructor is used by the MVC framework to instantiate the controller using
        // the default forms authentication and membership providers.

        public AccountController()
            : this(null, null)
        {
        }

        // This constructor is not used by the MVC framework but is instead provided for ease
        // of unit testing this type. See the comments at the end of this file for more
        // information.

        public AccountController(IFormsAuthentication formsAuth, MembershipProvider provider)
        {
            FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();
            //Provider = provider ?? Membership.Provider;
        }

        public IFormsAuthentication FormsAuth
        {
            get;
            private set;
        }

        //public MembershipProvider Provider
        //{
        //    get;
        //    private set;
        //}

        [Authorize]
        public ActionResult ChangePassword()
        {

            ViewData["Title"] = "Change Password";
            ViewData["PasswordLength"] = Settings.Default.MinRequiredPasswordLength;

            return this.PluginView();
        }

        [Authorize]
        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult ChangePassword(string currentPassword, string newPassword, string confirmPassword)
        {

            ViewData["Title"] = "Change Password";
            ViewData["PasswordLength"] = Settings.Default.MinRequiredPasswordLength;

            IAccountService accountService = ObjectFactory.GetInstance<IAccountService>();

            ServiceResponse response = accountService.AttemptChangePassword(
                new App.Account.Models.Forms.ChangePassword()
                {
                    ConfirmPassword = confirmPassword,
                    CurrentPassword = currentPassword,
                    NewPassword = newPassword,
                    UserName = User.Identity.Name
                });

            if (response.Successful)
            {
                    return RedirectToAction("~/Plugin/App.Account.dll/App.Account.Views.ChangePasswordSuccess.aspx");
            }
            else
                this.UpdateModelStateWithViolations(response.RuleViolations);

            // If we got this far, something failed, redisplay form
            return this.PluginView();
        }

        public ActionResult ChangePasswordSuccess()
        {

            ViewData["Title"] = "Change Password";

            return this.PluginView();
        }

        public ActionResult Login()
        {

            ViewData["Title"] = "Login";

            return this.PluginView();
        }

        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult Login(string username, string password, bool rememberMe, string returnUrl)
        {

            ViewData["Title"] = "Login";

            IAccountService accountService = ObjectFactory.GetInstance<IAccountService>();

            //Paging Demo
            //accountService.GetRolePage(new PageRequest
            //{
            //    Index = 2,
            //    PageSize = 10,
            //    Filters = new ContractList<Filter>(
            //        new[]{new Filter { BinaryExpression=FilterBinaryExpression.Equal, Parameter="Name", TypeName="String",Value="Admin"},
            //            new Filter { BinaryExpression=FilterBinaryExpression.GreaterThan, Parameter="Level", TypeName="Int32", Value=1}}),
            //    Sorts = new ContractList<Sort>(
            //        new[] { new Sort { Ascending = true, TypeName = "Int32", Parameter = "Level" } })
            //});
            ///* Executes
            //SELECT [t1].[RoleID] AS [ID], [t1].[Name], [t1].[Level] AS [Level]
            //FROM (
            //    SELECT ROW_NUMBER() OVER (ORDER BY [t0].[Level]) AS [ROW_NUMBER], [t0].[RoleID], [t0].[Name], [t0].[Level]
            //    FROM [dbo].[Role] AS [t0]
            //    WHERE ([t0].[Level] > 1) AND ([t0].[Name] = 'Admin')
            //    ) AS [t1]
            //WHERE [t1].[ROW_NUMBER] BETWEEN 20 + 1 AND 20 + 10
            //ORDER BY [t1].[ROW_NUMBER]
            //*/

            ServiceResponse<User> response = accountService.AttemptLogin(
                new App.Account.Models.Forms.Login()
                    {
                        UserName = username,
                        Password = password
                    });

            if (response.Successful)
            {
                FormsAuth.SetAuthCookie(response.Response.Name, rememberMe);
                
                if (!String.IsNullOrEmpty(returnUrl))
                {
                    return Redirect(returnUrl);
                }
                else
                {
                    return RedirectToAction("Index", "Home");
                }
            }
            else
                this.UpdateModelStateWithViolations(response.RuleViolations);

            // If we got this far, something failed, redisplay form
            ViewData["rememberMe"] = rememberMe;
            return this.PluginView();
        }

        public ActionResult Logout()
        {

            FormsAuth.SignOut();

            return RedirectToAction("Index", "Home");
        }

        protected override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            if (filterContext.HttpContext.User.Identity is WindowsIdentity)
            {
                throw new InvalidOperationException("Windows authentication is not supported.");
            }
        }

        public ActionResult Register()
        {

            ViewData["Title"] = "Register";
            ViewData["PasswordLength"] = Settings.Default.MinRequiredPasswordLength;

            return this.PluginView();
        }

        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult Register(string username, string email, string password, string confirmPassword)
        {

            ViewData["Title"] = "Register";
            ViewData["PasswordLength"] = Settings.Default.MinRequiredPasswordLength;


            IAccountService accountService = ObjectFactory.GetInstance<IAccountService>();

            ServiceResponse<User> response = accountService.AttemptRegister(
                new App.Account.Models.Forms.Register()
                {
                    UserName = username,
                    Password = password,
                    Email = email,
                    ConfirmPassword = confirmPassword
                });

            if (response.Successful)
            {
                FormsAuth.SetAuthCookie(response.Response.Name, false /* createPersistentCookie */);
                return RedirectToAction("Index", "Home");
            }
            else
                this.UpdateModelStateWithViolations(response.RuleViolations);
                    

            // If we got this far, something failed, redisplay form
            return this.PluginView();
        }
    }

    // The FormsAuthentication type is sealed and contains static members, so it is difficult to
    // unit test code that calls its members. The interface and helper class below demonstrate
    // how to create an abstract wrapper around such a type in order to make the AccountController
    // code unit testable.

    public interface IFormsAuthentication
    {
        void SetAuthCookie(string userName, bool createPersistentCookie);
        void SignOut();
    }

    public class FormsAuthenticationWrapper : IFormsAuthentication
    {
        public void SetAuthCookie(string userName, bool createPersistentCookie)
        {
            FormsAuthentication.SetAuthCookie(userName, createPersistentCookie);
        }
        public void SignOut()
        {
            FormsAuthentication.SignOut();
        }
    }
}
